﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CoolCode
{
    //public static class Validator
    //{
    //    public static ValidationHelper<T> CreateValidator<T>(this T value, string argName)
    //    {
    //        return new ValidationHelper<T>(value, argName);
    //    }
    //}

    public class ValidationHelper<T>
    {
        #region 成员

        private T _Value;

        private string _Name;

        #endregion

        #region 属性

        /// <summary>
        /// 获取待验证的参数的值.
        /// </summary>
        public T Value
        {
            get
            {
                return _Value;
            }
        }

        /// <summary>
        /// 获取待验证的参数的名称.
        /// </summary>
        public string Name
        {
            get
            {
                return _Name;
            }
        }

        #endregion

        #region 构造函数

        /// <summary>
        /// 创建一个<see cref="ValidationHelper&lt;T&gt;"/>的对象.
        /// </summary>
        /// <param name="value">待验证的参数的值.</param>
        /// <param name="name">待验证的参数的名称.</param>
        public ValidationHelper(T value, string name)
        {
            _Value = value;
            _Name = name;
        }

        #endregion

        #region 基本方法

        /// <summary>
        /// 验证参数不为其默认值.
        /// </summary>
        /// <returns>this指针以方便链式调用.</returns>
        /// <exception cref="ArgumentException">参数为值类型且为默认值.</exception>
        /// <exception cref="ArgumentNullException">参数为引用类型且为null.</exception>
        public ValidationHelper<T> NotDefault()
        {
            if (Value.Equals(default(T)))
            {
                if (Value is ValueType)
                {
                    throw new ArgumentException(
                        String.Format("参数{0}不能使用默认值", Name), Name);
                }
                else
                {
                    throw new ArgumentNullException(
                        String.Format("参数{0}不能为null", Name), Name);
                }
            }

            return this;
        }

        /// <summary>
        /// 使用自定义方法进行验证.
        /// </summary>
        /// <param name="rule">用以验证的自定义方法.</param>
        /// <returns>this指针以方便链式调用.</returns>
        /// <exception cref="Exception">验证失败抛出相应异常.</exception>
        /// <remarks><paramref name="rule"/>的第一个参数为参数值,第二个参数为参数名称.</remarks>
        public ValidationHelper<T> CustomRule(Action<T, string> rule)
        {
            rule(Value, Name);

            return this;
        }

        #endregion
    }

    public static class StringValidationHelper
    {
        private static bool IsEmpty(ValidationHelper<string> current  )
        {
            return string.IsNullOrEmpty(current.Value);
        }

        /// <summary>
        /// 验证<see cref="System.String"/>类型的参数不为空.
        /// </summary>
        /// <param name="current">用于验证的<see cref="ValidationHelper&lt;T&gt;"/></param>
        /// <returns><paramref name="current"/>的引用以方便链式调用.</returns>
        public static ValidationHelper<string> NotEmpty(this ValidationHelper<string> current)
        {
            current.NotDefault();

            if (current.Value.Length == 0)
            {
                throw new ErrorException(current.Name, "E0033");
            }

            return current;
        }

        /// <summary>
        /// 验证<see cref="System.String"/>类型的参数的长度小于一定值.
        /// </summary>
        /// <param name="current">用于验证的<see cref="ValidationHelper&lt;T&gt;"/></param>
        /// <param name="length">可行的最大长度(包括此值).</param>
        /// <returns><paramref name="current"/>的引用以方便链式调用.</returns>
        public static ValidationHelper<string> ShorterThan(this ValidationHelper<string> current, int length)
        {
            if (IsEmpty(current)) return current ;

            if (current.Value.Length > length)
            {
                throw new ErrorException(current.Name, "E0034", length);
            }

            return current;
        }

        /// <summary>
        /// 验证<see cref="System.String"/>类型的参数的长度大于一定值.
        /// </summary>
        /// <param name="current">用于验证的<see cref="ValidationHelper&lt;T&gt;"/></param>
        /// <param name="length">可行的最小长度(包括此值).</param>
        /// <returns><paramref name="current"/>的引用以方便链式调用.</returns>
        public static ValidationHelper<string> LongerThan(this ValidationHelper<string> current, int length)
        {
            if (IsEmpty(current)) return current;

            if (current.Value.Length < length)
            {
                throw new ErrorException(current.Name, "E0035", length);
            }

            return current;
        }

        /// <summary>
        /// 验证<see cref="System.String"/>类型的参数的长度在一定值之间.
        /// </summary>
        /// <param name="current">用于验证的<see cref="ValidationHelper&lt;T&gt;"/></param>
        /// <param name="minLength">可行的最小长度(包括此值).</param>
        /// <param name="maxLength">可行的最大长度(包括此值).</param>
        /// <returns><paramref name="current"/>的引用以方便链式调用.</returns>
        public static ValidationHelper<string> Between(this ValidationHelper<string> current, int minLength, int maxLength)
        {
            if (IsEmpty(current)) return current;

            if (current.Value.Length < minLength || current.Value.Length > maxLength)
            {
                throw new ErrorException(current.Name, "E0036",  minLength, maxLength) ;
            }

            return current;
        }

        /// <summary>
        /// 验证<see cref="System.String"/>类型的参数是Email格式.
        /// </summary>
        /// <param name="current">用于验证的<see cref="ValidationHelper&lt;T&gt;"/></param> 
        /// <returns><paramref name="current"/>的引用以方便链式调用.</returns>
        public static ValidationHelper<string> IsEmail(this ValidationHelper<string> current)
        {
            if (IsEmpty(current)) return current;

            if (!current.Value.IsEmail())
            {
                throw new ErrorException(current.Name, "E0037" );
            }

            return current;
        }
    }
}
